package com.nervenets.general.web;

import com.nervenets.general.annotation.ProhibitDuplicateRequest;
import com.nervenets.general.aspect.SysLog;
import com.nervenets.general.entity.ResponseResult;
import com.nervenets.general.enumeration.Action;
import com.nervenets.general.exception.LogicException;
import com.nervenets.general.hibernate.TreeDomainObject;
import com.nervenets.general.jwt.aspect.JwtSecurity;
import com.nervenets.general.service.TreeService;
import com.nervenets.general.web.params.*;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 树实体基础 BaseTreeEntityController
 *
 * @param <T>   实体类
 * @param <S>   实体服务类
 * @param <F>   实体表单参数类
 * @param <P>   实体分页参数数
 * @param <TQP> 自定义树参数
 * @param <LR>  列表返回实体
 * @param <DR>  详情返回实体
 */
@Slf4j
public abstract class BaseTreeEntityController<
        T extends TreeDomainObject<T>,
        S extends TreeService<T>,
        F extends TreeFormParams<T, S>,
        P extends EntityPagingParams<T>,
        TQP extends TreeQueryParams<T>, LR, DR>
        extends BaseEntityController<T, S, F, P, LR, DR> {

    @SysLog
    @ApiOperation(value = "禁用启用")
    @PostMapping("/enable")
    @JwtSecurity(permission = "enable", permissionName = "{application.permission.name.enable}")
    @ProhibitDuplicateRequest
    public ResponseEntity<ResponseResult<Void>> enable(@ApiParam(name = "params", value = "参数实体", required = true) @Valid @RequestBody BoolIdsParams params, HttpServletRequest request, HttpServletResponse response) throws InstantiationException, IllegalAccessException {
        Class<F> formEntityClass;
        Class<T> entityClass;
        final Type[] arguments = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
        entityClass = (Class<T>) arguments[0];
        formEntityClass = (Class<F>) arguments[2];

        HashMap<Long, F> formParamsMap = new HashMap<>();

        List<T> ts = new ArrayList<>();
        for (Long targetId : params.getTargetIds()) {
            T t = service.findOne(targetId);
            if (null == t || t.isDeleted()) throw new LogicException(404, "您要操作的数据不存在");
            final F f = formEntityClass.newInstance();
            f.bindOld(entityClass, t);
            f.setFormId(t.getId());
            t.setEnable(params.isYes());
            f.bindNow(entityClass, t);
            formParamsMap.put(targetId, f);
            before(Action.update, f, request, response);
            ts.add(t);
        }
        service.saveAll(ts);
        ts.forEach(t -> after(Action.update, t, formParamsMap.get(t.getId()), request, response));
        return successMessage();
    }

    @ApiOperation(value = "树(自定义条件)")
    @GetMapping("/trees/query")
    public ResponseEntity<ResponseResult<List<T>>> trees(@ApiParam(name = "params", value = "参数实体", required = true) @Valid TQP params, HttpServletRequest request, HttpServletResponse response) {
        setJsonIgnoreEnv("trees", request);
        return successMessage(service.getTrees(params));
    }

    @ApiOperation(value = "树")
    @GetMapping("/trees")
    public ResponseEntity<ResponseResult<List<T>>> trees(
            @ApiParam(name = "all", value = "当为true时，返回所有，否则只返回启用的，默认false", defaultValue = "false", required = true)
            @RequestParam(name = "all", defaultValue = "false") boolean all, HttpServletRequest request, HttpServletResponse response) {
        setJsonIgnoreEnv("trees", request);
        DefaultTreeQueryParams<T> params = new DefaultTreeQueryParams<>();
        params.setParentId(0);
        params.setAll(all);
        return successMessage(service.getTrees(params));
    }

    @ApiOperation(value = "直属下级列表")
    @PostMapping("/children")
    public ResponseEntity<ResponseResult<List<T>>> children(@ApiParam(name = "params", value = "参数实体", required = true) @Valid @RequestBody IdParams params, HttpServletRequest request, HttpServletResponse response) {
        setJsonIgnoreEnv("list", request);
        return successMessage(service.findChildrenByParentId(params.getTargetId()));
    }

    @ApiOperation(value = "所有下级列表")
    @PostMapping("/children/all")
    public ResponseEntity<ResponseResult<List<T>>> childrenAll(@ApiParam(name = "params", value = "参数实体", required = true) @Valid @RequestBody IdParams params, HttpServletRequest request, HttpServletResponse response) {
        setJsonIgnoreEnv("list", request);
        return successMessage(service.findAllChildrenByParentId(params.getTargetId()));
    }

    @ApiOperation(value = "父级列表")
    @PostMapping("/parents")
    public ResponseEntity<ResponseResult<List<T>>> parents(@ApiParam(name = "params", value = "参数实体", required = true) @Valid @RequestBody IdParams params, HttpServletRequest request, HttpServletResponse response) {
        setJsonIgnoreEnv("list", request);
        return successMessage(service.findParentsById(params.getTargetId(), true));
    }
}
